// v2010.09.21

/*
Copyright (c) 2010 Ben Hendel-Doying

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

package world;

import game.ASCII;

import java.awt.Graphics;
import java.util.ArrayList;

public final class Tile
{
	private Scenery object = null;
	private Actor creature = null;
	private ArrayList<Item> items = new ArrayList<Item>();
	private int obol = 0;
	private World world;
	private int x, y;
	private int cur_demonism, max_demonism;
	private boolean sanctuary = false;

	private int min_distance_from_wall = 0;

	boolean draw_me = true;

	private static int steps_since_last_gate = 0;
	private static int steps_since_last_shop = 1500;
	private static int steps_since_last_demon = 0;

	private static int steps_since_last_cavern = 410;

	private Appearance appearance = DEFAULT_APPEARANCE;

	public static final Appearance DEFAULT_APPEARANCE = new Appearance((char)250, ASCII.COLOR_DARK_GRAY);
	public static final Appearance SANCTUARY_APPEARANCE = new Appearance((char)250, ASCII.COLOR_WHITE);
	public static final Appearance OBOL_APPEARANCE = new Appearance((char)9, ASCII.COLOR_LIGHT_GRAY);

	Tile(World w, Actor a, int x, int y, int dist, int demon)
	{
		this(w, a, x, y, dist, demon, true);
	}

	Tile(World w, Actor a, int x, int y, int dist, int demon, boolean not_empty)
	{
		world = w;
		this.x = x;
		this.y = y;
		max_demonism = demon + World.RNG.nextInt(2 + World.RNG.nextInt(2));
		cur_demonism = max_demonism;

		steps_since_last_cavern++;

		if(dist == 0)
			min_distance_from_wall = 0;
		else if(steps_since_last_cavern >= 500)
		{
			min_distance_from_wall = 6;

			if(steps_since_last_cavern >= 505)
				steps_since_last_cavern = 0;
		}
		else if(World.RNG.nextInt(17 + dist) == 0)
			min_distance_from_wall = dist + 2 + World.RNG.nextInt(4);
		else if(World.RNG.nextInt(3) == 0)
			min_distance_from_wall = dist + 1;
		else
			min_distance_from_wall = dist;

		if(min_distance_from_wall == 0)
			AddScenery(new Wall());

		if(not_empty)
		{
			steps_since_last_gate++;
			steps_since_last_shop++;
			steps_since_last_demon++;

			if(min_distance_from_wall == 0)
				;
			else if(steps_since_last_gate >= 2000 && World.RNG.nextInt(3000) == 0)
			{
				Gate g = new Gate();
				AddScenery(g);
				steps_since_last_gate = 0;
				a.MemorizeGate(g);
			}
			else if(steps_since_last_shop >= 1000 && World.RNG.nextInt(2000) == 0)
			{
				Shop s = new Shop(max_demonism);
				AddScenery(s);
				steps_since_last_shop = 0;
			}
			else if(steps_since_last_demon >= 10 && World.RNG.nextInt(30) == 0)
			{
				Demon d = new Demon(Actor.INTELLIGENCE_ARTIFICIAL, max_demonism);
				AddCreature(d);
				w.AddMonster(d);
				steps_since_last_demon = 0;
			}

			if(object == null && World.RNG.nextInt(450) <= 0)
				AddItem(w.CreateTreasure((int)Math.ceil((demon + a.GetGehenna()) / 10.0)));
		}
	}

	public boolean IsTransparent() { return !IsOpaque(); }

	public boolean IsOpaque()
	{
		if(object == null)
			return false;
		else
			return object.IsOpaque();
	}

	public int GetMinimumDistanceFromWall() { return min_distance_from_wall; }

	public int GetDemonism() { return cur_demonism; }
	public int GetMaxDemonism() { return max_demonism; }

	public World GetWorld() { return world; }
	public int GetX() { return x; }
	public int GetY() { return y; }

	public Tile GetNorth() { return world.GetTile(x, y - 1); }
	public Tile GetNE() { return world.GetTile(x + 1, y - 1); }
	public Tile GetEast() { return world.GetTile(x + 1, y); }
	public Tile GetSE() { return world.GetTile(x + 1, y + 1); }
	public Tile GetSouth() { return world.GetTile(x, y + 1); }
	public Tile GetSW() { return world.GetTile(x - 1, y + 1); }
	public Tile GetWest() { return world.GetTile(x - 1, y); }
	public Tile GetNW() { return world.GetTile(x - 1, y - 1); }

	public void UpdateAppearance()
	{
		if(creature != null)
			appearance = creature.appearance;
		else if(object != null)
			appearance = object.appearance;
		else if(items.size() > 1 || (obol > 0 && items.size() == 1))
			appearance = new Appearance((char)15, items.get(items.size() - 1).appearance.GetColor());
		else if(items.size() == 1)
			appearance = items.get(0).appearance;
		else if(obol > 0)
			appearance = OBOL_APPEARANCE;
		else if(sanctuary)
			appearance = SANCTUARY_APPEARANCE;
		else
			appearance = DEFAULT_APPEARANCE;
	}

	public void SetMinimumDistanceFromWall(int d)
	{
		min_distance_from_wall = d;
	}

	public boolean AddScenery(Scenery o)
	{
		if(object != null || creature != null || items.size() > 0)
			return false;
		else
		{
			if(o.location != null)
				o.location.RemoveScenery();

			o.location = this;
			object = o;

			UpdateAppearance();

			return true;
		}
	}

	public boolean ReplaceScenery(Scenery o)
	{
		RemoveScenery();
		return AddScenery(o);
	}

	public boolean AddCreature(Actor o)
	{
		if((object != null && object.IsBlocking()) || creature != null)
			return false;
		else
		{
			if(o.location != null)
				o.location.RemoveCreature();

			o.location = this;
			creature = o;

			UpdateAppearance();

			return true;
		}
	}

	public boolean AddItem(Item o)
	{
		if(object != null && object.IsBlocking())
			return false;
		else
		{
			items.add(o);

			UpdateAppearance();

			return true;
		}
	}

	public void RemoveScenery()
	{
		if(object != null)
		{
			object.location = null;
			object = null;
			UpdateAppearance();
		}
	}

	public void RemoveCreature()
	{
		if(creature != null)
		{
			creature.location = null;
			creature = null;
			UpdateAppearance();
		}
	}

	public Item GetFirstItem() { return items.get(0); }

	public void RemoveFirstItem()
	{
		items.remove(0);
		UpdateAppearance();
	}

	public Scenery GetScenery() { return object; }
	public Actor GetCreature() { return creature; }

	public boolean IsBlocking() { return(object != null && object.IsBlocking()); }

	public void Render(Graphics g, int x, int y)
	{
		if(draw_me)
			appearance.Render(g, x, y);
	}

	public void Draw(boolean d) { draw_me = d; }

	public boolean IsSanctuary() { return sanctuary; }

	public int ItemCount() { return items.size(); }
	public boolean HasItems() { return(items.size() > 0); }
	public ArrayList<Item> GetItems() { return items; }
	public void ClearItems() { items.clear(); }

	public int GetObol() { return obol; }
	public void AddObol(int a)
	{
		obol += a;
		UpdateAppearance();
	}

	public int TakeObol()
	{
		int a = obol;
		obol = 0;
		return a;
	}
}
